<template>
  <n-modal
    v-bind="$attrs"
    v-model:show="showModel"
    class="pro-modal"
    :class="`pro-modal__${componentStyle.modalStyle}`"
    preset="card"
    :style="modalStyle"
    :segmented="{
      content: 'soft',
      footer: 'soft'
    }"
    :auto-focus="false"
    @afterLeave="handleAfterLeave"
  >
    <template #header>
      <slot v-if="$slots['header']" name="header"></slot>
      <span v-else>{{ $attrs.title }}</span>
    </template>
    <template #header-extra>
      <slot name="header-extra"></slot>
      <div
        v-if="fullscreen"
        class="fullscreen-btn"
        @click="handleFullscreenChange"
      >
        <icons name="icon-fullscreen" size="18" />
      </div>
    </template>

    <template v-if="skeleton">
      <n-skeleton text style="width: 60%" />
      <n-skeleton text :repeat="6" />
    </template>
    <template v-else>
      <n-spin :show="loading" :description="loadingTip">
        <div class="pro-modal_content">
          <n-scrollbar
            ref="scrollWrapRef"
            :style="{ maxHeight: contentMaxHeight }"
            trigger="none"
            @scroll="watchScroll"
          >
            <slot></slot>
          </n-scrollbar>
          <!-- <div v-show="!isScrollBottom" class="footer-shadow"></div> -->
        </div>
      </n-spin>
    </template>

    <template #footer>
      <slot v-if="$slots['footer']" name="footer"></slot>
      <div v-else-if="showFooter" class="pro-modal_footer">
        <n-space :justify="footAlign">
          <n-button v-if="showCancelBtn" @click="emits('update:show', false)">
            {{ cancelText }}
          </n-button>
          <n-button
            v-if="showOkBtn"
            type="primary"
            :loading="loading"
            :disabled="skeleton"
            @click="$emit('ok')"
          >
            {{ okText }}
          </n-button>
        </n-space>
      </div>
    </template>
  </n-modal>
</template>

<script lang="ts" setup>
  import { useModalDragMove } from './useModalDrag'
  import themeConfig from '@/config/theme.config'
  import { throttle } from 'lodash-es'
  const { componentStyle } = themeConfig

  const props = defineProps({
    show: {
      type: Boolean,
      default: false
    },
    style: {
      type: Object,
      default: () => ({})
    },
    // 是否显示取消按钮
    showCancelBtn: {
      type: Boolean,
      default: true
    },
    // 是否显示确认按钮
    showOkBtn: {
      type: Boolean,
      default: true
    },
    // 是否显示弹窗底部
    showFooter: {
      type: Boolean,
      default: true
    },
    // 取消按钮的文案
    cancelText: {
      type: String,
      default: '取消'
    },
    // 确认按钮的文案
    okText: {
      type: String,
      default: '确认'
    },
    // 底部的布局排列
    footAlign: {
      type: String,
      default: 'right'
    },
    // 加载状态
    loading: {
      type: Boolean,
      default: false
    },
    // 加载状态的提示
    loadingTip: {
      type: String,
      default: '加载中...'
    },
    // 骨架屏状态
    skeleton: {
      type: Boolean,
      default: false
    },
    // 是否开启拖拽
    draggable: {
      type: Boolean,
      default: true
    },
    // 是否满屏
    fullscreen: {
      type: Boolean,
      default: true
    },
    // 固定高度
    height: Number,
    // 最小高度
    minHeight: Number,
    // 最大高度
    maxHeight: Number,
    // 是否动态高度的弹窗高度限制于屏幕内
    inScreen: {
      type: Boolean,
      default: true
    },
    // 弹窗宽度
    width: {
      type: [String, Number],
      default: 600
    }
  })

  const emits = defineEmits([
    'update:show',
    'ok',
    'afterLeave',
    'fullscreenChange',
    'contentHeight'
  ])
  const scrollWrapRef = ref<any>(null)
  const { show: visible, draggable } = toRefs(props)
  const isFullscreen = ref(false)
  const screenHeight = ref(document.body.clientHeight)
  const isScrollBottom = ref(false)

  useModalDragMove({
    draggable,
    visible
  })

  const showModel = computed({
    set(value) {
      emits('update:show', value)
    },
    get() {
      return props.show
    }
  })

  const modalStyle = computed(() => {
    if (isFullscreen.value) {
      return {
        ...props.style,
        width: '100%',
        height: '100vh',
        top: '0px',
        left: '0px'
      }
    }

    const style = {}
    if (props.height) {
      style['height'] = props.height + 'px'
    }

    if (props.minHeight) {
      style['minHeight'] = props.minHeight + 'px'
    }

    return {
      width: props.width + 'px',
      ...style,
      ...props.style
    }
  })

  const contentMaxHeight = computed(() => {
    let contentHeight: any = null
    if (isFullscreen.value) {
      contentHeight = screenHeight.value - 140
    } else if (props.maxHeight) {
      contentHeight = Math.max(props.maxHeight - 140, 100)
    } else if (props.height) {
      contentHeight = props.height - 160
    } else if (props.inScreen) {
      contentHeight = screenHeight.value - 160
    }
    if (!props.showFooter) contentHeight += 60
    emits('contentHeight', contentHeight)
    return contentHeight ? contentHeight + 'px' : null
  })

  const handleAfterLeave = (show) => {
    emits('afterLeave', show)
  }

  const handleFullscreenChange = () => {
    isFullscreen.value = !isFullscreen.value
    emits('fullscreenChange', isFullscreen)
  }

  const setScreenHeight = () => {
    screenHeight.value = document.body.clientHeight
  }

  watch(scrollWrapRef, () => {
    if (scrollWrapRef.value) {
      const scrollbarInstRef = scrollWrapRef.value.scrollbarInstRef
      const containerRef = scrollbarInstRef.containerRef as HTMLDivElement
      const contentRef = scrollbarInstRef.contentRef as HTMLDivElement

      if (containerRef.clientHeight >= contentRef.clientHeight) {
        isScrollBottom.value = true
      }
    }
  })

  const watchScroll = throttle((e: Event) => {
    if (scrollWrapRef.value) {
      const scrollWrapEl = e.target as HTMLDivElement
      const clientHeight = scrollWrapEl.clientHeight
      const scrollTop = scrollWrapEl.scrollTop
      const scrollHeight = scrollWrapEl.scrollHeight
      isScrollBottom.value = scrollHeight - clientHeight === scrollTop + 0.5
    }
  }, 100)

  onMounted(() => {
    window.addEventListener('resize', setScreenHeight)
  })
  onUnmounted(() => {
    window.removeEventListener('resize', setScreenHeight)
  })
</script>

<style lang="less">
  @import './styles.less';
  .pro-modal {
    .n-card-header {
      padding: 16px !important;
    }

    .n-card__content {
      margin: 0px !important;
      padding: 14px !important;
      overflow: hidden;
    }

    .n-card__footer {
      margin: 0px !important;
      padding: 10px 16px !important;
    }

    .fullscreen-btn {
      width: 22px;
      height: 22px;

      display: flex;
      align-items: center;
      justify-content: center;
    }

    .fullscreen-btn:hover {
      background-color: #e8e8e8;
      border-radius: 5px;
    }

    .pro-modal_content {
      position: relative;

      .footer-shadow {
        position: absolute;
        z-index: 99;
        bottom: -20px;
        left: -12px;
        right: -12px;
        height: 5px;
        box-shadow: rgba(17, 17, 26, 0.14) 0px -10px 15px;
      }
    }
  }
</style>
